package com.dqx.opengl_es_demo.model.spirit;

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.opengl.GLES20;

import com.dqx.opengl_es_demo.model.utils.MatrixState;
import com.dqx.opengl_es_demo.model.utils.ShaderUtil;
import com.dqx.opengl_es_demo.model.utils.TextureUtil;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

/**
 * 绘制模型的工具类（针对有材质纹理的模型）
 */
public class LeGLObjTextureSpirit extends LeGLBaseSpirit {
    //着色器程序id
    int mProgram;

    //总变换矩阵句柄
    int muMVPMatrixHandle;
    //模型的变换矩阵句柄
    int muMMatrixHandle;
    //顶点位置属性句柄
    int maPositionHandle;
    //顶点法向量属性句柄
    int maNormalHandle;
    //光源位置属性句柄
    int maLightLocationHandle;
    //摄像机位置属性句柄
    int maCameraHandle;
    //顶点纹理坐标属性句柄
    int maTexCoorHandle;
    //材质中透明度句柄
    int muOpacityHandle;

    //顶点着色器代码脚本
    String mVertexShader;
    //片元着色器代码脚本
    String mFragmentShader;

    //顶点坐标缓冲
    FloatBuffer mVertexBuffer;
    //顶点法向量缓冲
    FloatBuffer mNormalBuffer;
    //顶点纹理坐标缓冲
    FloatBuffer mTexCoorBuffer;

    //材质中透明度
    protected float mAlpha;
    //需转化为纹理的图片
    protected Bitmap mBmp;
    //顶点个数
    int vCount = 0;

    //纹理id
    protected int textureId;

    /**
     * 构造函数
     *
     * @param res
     * @param vertices 顶点坐标
     * @param normals  法向量
     * @param texCoors 纹理坐标
     * @param alpha    透明度
     * @param bmp      纹理贴图
     */
    public LeGLObjTextureSpirit(Resources res, float[] vertices, float[] normals, float texCoors[], float alpha, Bitmap bmp) {
        //初始化顶点坐标与着色数据
        initVertexData(vertices, normals, texCoors, alpha, bmp);
        //初始化shader
        initShader(res);
        // 加载纹理
        initTexture();
    }

    /**
     * 初始化顶点坐标、法向量和纹理坐标
     *
     * @param vertices 顶点坐标
     * @param normals  法向量
     * @param texCoors 纹理坐标
     * @param alpha    透明度
     * @param bmp      纹理贴图
     */
    public void initVertexData(float[] vertices, float[] normals, float texCoors[], float alpha, Bitmap bmp) {
        this.mAlpha = alpha;
        this.mBmp = bmp;
        //顶点个数
        vCount = vertices.length / 3;

        //初始化顶点坐标缓冲
        ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
        vbb.order(ByteOrder.nativeOrder());
        mVertexBuffer = vbb.asFloatBuffer();
        mVertexBuffer.put(vertices);
        mVertexBuffer.position(0);

        //初始化法向量缓冲
        ByteBuffer cbb = ByteBuffer.allocateDirect(normals.length * 4);
        cbb.order(ByteOrder.nativeOrder());
        mNormalBuffer = cbb.asFloatBuffer();
        mNormalBuffer.put(normals);
        mNormalBuffer.position(0);

        //初始化纹理坐标缓冲
        ByteBuffer tbb = ByteBuffer.allocateDirect(texCoors.length * 4);
        tbb.order(ByteOrder.nativeOrder());
        mTexCoorBuffer = tbb.asFloatBuffer();
        mTexCoorBuffer.put(texCoors);
        mTexCoorBuffer.position(0);
    }

    /**
     * 初始化着色器
     *
     * @param res
     */
    public void initShader(Resources res) {
        //加载顶点着色器
        mVertexShader = ShaderUtil.loadFromAssetsFile("shader/texture_vertex.sh", res);
        //加载片元着色器
        mFragmentShader = ShaderUtil.loadFromAssetsFile("shader/texture_frag.sh", res);
        //创建着色器程序
        mProgram = ShaderUtil.createProgram(mVertexShader, mFragmentShader);
        //获取顶点坐标属性句柄
        maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
        //获取顶点法向量属性句柄
        maNormalHandle = GLES20.glGetAttribLocation(mProgram, "aNormal");
        //获取总变换矩阵句柄
        muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
        //获取模型的变换矩阵句柄
        muMMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMMatrix");
        //获取光源位置句柄
        maLightLocationHandle = GLES20.glGetUniformLocation(mProgram, "uLightLocation");
        //获取程纹理坐标属性句柄
        maTexCoorHandle = GLES20.glGetAttribLocation(mProgram, "aTexCoor");
        //获取摄像机位置句柄
        maCameraHandle = GLES20.glGetUniformLocation(mProgram, "uCamera");
        //获取透明度属性句柄
        muOpacityHandle = GLES20.glGetUniformLocation(mProgram, "uOpacity");
    }

    /**
     * 加载纹理
     */
    private void initTexture() {
        if (mBmp != null) {
            textureId = TextureUtil.getTextureIdByBitmap(mBmp);
        }
    }

    /**
     * 执行绘制
     */
    @Override
    public void draw() {
        //使用着色器程序
        GLES20.glUseProgram(mProgram);
        //设置总变换矩阵的值
        GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, MatrixState.getFinalMatrix(), 0);
        //设置模型变换矩阵的值
        GLES20.glUniformMatrix4fv(muMMatrixHandle, 1, false, MatrixState.getMMatrix(), 0);
        //设置光源位置的值
        GLES20.glUniform3fv(maLightLocationHandle, 1, MatrixState.lightPositionFB);
        //设置摄像机位置的值
        GLES20.glUniform3fv(maCameraHandle, 1, MatrixState.cameraFB);
        //设置顶点坐标的值
        GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false, 3 * 4, mVertexBuffer);
        //设置法向量的值
        GLES20.glVertexAttribPointer(maNormalHandle, 3, GLES20.GL_FLOAT, false, 3 * 4, mNormalBuffer);
        //设置纹理坐标的值
        GLES20.glVertexAttribPointer(maTexCoorHandle, 2, GLES20.GL_FLOAT, false, 2 * 4, mTexCoorBuffer);
        //设置材质透明度的值
        GLES20.glUniform1f(muOpacityHandle, mAlpha);

        //启用纹理坐标属性
        GLES20.glEnableVertexAttribArray(maTexCoorHandle);
        //启用顶点坐标属性
        GLES20.glEnableVertexAttribArray(maPositionHandle);
        //启用法向量属性
        GLES20.glEnableVertexAttribArray(maNormalHandle);

        //集合纹理单元0
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        //绑定纹理单元0
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);

        //绘制
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vCount);
    }

}
